第 9 章:Gateway 管理對外服務
除了直接使用 Service 和 Ingress 之外,Kubernetes 社區還發起了 Gateway API 項目,它可以幫助我們將 Kubernetes 中的服務暴露到集群外。
Gateway API 是一個由 SIG-NETWORK 管理的開源項目。該項目的目標是在 Kubernetes 生態系統中發展服務網絡 API。Gateway API 提供了暴露 Kubernetes 應用的資源——GatewayClass、Gateway、HTTPRoute、TCPRoute 等。
Gateway API 已經得到了大量的網關和服務網格項目支持,請在 Gateway 官方文檔中查看支持狀況。
Gateway 目標
Gateway API 旨在通過提供表現性的、可擴展的、面向角色的接口來改善服務網絡,這些接口由許多廠商實現,並得到了業界的廣泛支持。
Gateway API 是一個 API 資源的集合 —— GatewayClass、Gateway、HTTPRoute、TCPRoute 等。使用這些資源共同為各種網絡用例建模。
下圖中展示的是 Kubernetes 集群中四層和七層的網絡配置。從圖中可以看到通過將這些資源對象分離,可以實現配置上的解耦,由不同角色的人員來管理,而這也是 Gateway API 的相較於 Ingress 的一大特色。
Gateway API 與 Ingress 有什麽不同
Ingress 的主要目標是用簡單的、聲明性的語法來暴露 HTTP 應用。Gateway API 暴露了一個更通用的代理 API,可以用於更多的協議,而不僅僅是 HTTP,並為更多的基礎設施組件建模,為集群運營提供更好的部署和管理選項。
Gateway 相較於 Ingress 做了哪些改進
以下是 Gateway API 對 Ingress 的改進點。
- 更具表現力
- Gateway 表達了更多的核心功能,比如基於頭的匹配、流量加權和其他功能,而這些功能在 Ingress 中只能通過自定義方式實現。
- 更具擴展性
- Gateway API 允許在 API 的各個層次上鏈接自定義資源。這就允許在 API 結構的適當位置進行更精細的定制。
- 面向角色
- 它們被分離成不同的 API 資源,這些資源映射到 Kubernetes 上運行應用程序的常見角色。
- 通用性
- 這不是一種改進,而是應該保持不變。正如 Ingress 是一個具有眾多實現的通用規範一樣,Gateway API 被設計成一個由許多實現支持的可移植規範。
- 共享網關
- 它們允許獨立的路由資源綁定到同一個網關,從而實現負載均衡器和 VIP 的共享。這允許團隊安全地共享基礎設施,而不需要直接協調。
- 類型化後端引用
- 通過類型化後端引用,Routes 可以引用 Kubernetes 服務,也可以引用任何一種被設計為 Gateway 後端的 Kubernetes 資源。
- 跨命名空間引用
- 跨越不同 Namespaces 的路由可以綁定到網關。這樣,盡管對工作負載進行了命名空間劃分,但仍可共享網絡基礎設施。
- 類
- GatewayClass 將負載均衡實現的類型形式化。這些類使用戶可以很容易和明確地了解資源模型本身有什麽樣的能力。
在了解了 Gateway API 的目的後,接下來我們再看下它的資源模型、請求流程、TLS 配置及擴展點等。
角色劃分
Gateway API 開發者為其使用場景定義四類角色:
- 基礎設施提供方:如 AWS、GKE 等
- 集群運維:管理整個集群的計算、存儲、網絡、安全等
- 應用程序開發者:為自己開發的應用負責,管理應用的健壯性
- 應用管理員:不是所有的公司都有,通常在一些覆雜系統中會有專門的應用管理員 Gateway API 通過 Kubernetes 服務網絡的面向角色的設計在分布式靈活性和集中控制之間取得了平衡。使得許多不同的非協調團隊可以使用共享網絡基礎設施(硬件負載均衡器、雲網絡、集群托管代理等),所有團隊都受集群運維設置的策略約束。下圖展示了在進行 Gateway 管理時的角色劃分。
集群運維人員創建從 GatewayClass 派生的 Gateway 資源。此 Gateway 部署或配置它所代表的底層網絡資源。通過 Gateway 和 Route 之間的路由附加進程 ,集群運維人員和特定團隊必須就可以附加到此 Gateway 並通過它公開其應用程序的內容達成一致。集群運維人員可以在網關上實施 TLS 集中式策略。同時,Store 和 Site 團隊在他們自己的 Namespaces 中運行,但是將他們的 Routes 附加到同一個共享 Gateway,允許他們獨立控制自己的路由邏輯。這種關注點分離允許 Store 隊管理自己的流量拆分部署,同時將集中策略和控制權留給集群運維人員。
這種靈活性技能保持 API 的標準和可移植性,還使其可以適應截然不同的組織模型和實現。
資源模型
資源最初將作為 CRD 存在於 networking.x-k8s.io API 組中。未限定的資源名稱將隱含在該 API 組中。
Gateway API 的資源模型中,主要有三種類型的對象:
- GatewayClass:定義了一組具有共同配置和行為的網關。
- Gateway:流量請求端點,流量從這里被翻譯成集群內的服務。
- Route:描述了通過 Gateway 而來的流量如何映射到服務。
GatewayClass
GatewayClass 定義了一組共享共同配置和行為的 Gateway,每個 GatewayClass 由一個控制器處理,但控制器可以處理多個 GatewayClass。
GatewayClass 是一個集群範圍的資源。必須至少定義一個 GatewayClass,Gateway 才能夠生效。實現 Gateway API 的控制器通過關聯的 GatewayClass 資源來實現,用戶可以在自己的 Gateway 中引用該資源。
這類似於 Ingress 的 IngressClass 和 PersistentVolumes 的 StorageClass。在 Ingress v1beta1 中,最接近 GatewayClass 的是 ingress-class 注解,而在 Ingress V1 中,它的作用與 IngressClass 一樣。
kind: GatewayClass
metadata:
name: cluster-gateway
spec:
controllerName: "example.net/gateway-controller"
GatewayClass 一般由基礎設施提供商來創建,用戶不需要關注控制器如何實現,只需要了解該 GatewayClass 創建的對應 Gateway 的屬性即可。
Gateway API 的提供者還可以開放了一部分參數配置給網關管理員,管理員可以使用 GatewayClass.spec.parametersRef 字段來配置:
kind: GatewayClass
metadata:
name: internet
spec:
controllerName: "example.net/gateway-controller" # 该字段的值应为集群唯一的
parametersRef:
group: example.net/v1alpha1
kind: Config
name: internet-gateway-config
---
apiVersion: example.net/v1alpha1
kind: Config
metadata:
name: internet-gateway-config
spec:
ip-address-pool: internet-vips
...
建議使用 GatewayClass.spec.parametersRef 自定義資源配置,不過你也可以使用 ConfigMap。
在剛部署 GatewayClass 後,GatewayClass.status 中的狀態類型為 Accepted 但是 status 為 False,控制器處理完配置後 status 將變為 True,如果在該過程中出現錯誤,那麽會顯示在狀態中,如下所示。
kind: GatewayClass
...
status:
conditions:
- type: Accepted
status: False
Reason: BadFooBar
Message: "foobar" is an FooBar.
Gateway
Gateway 描述了如何將流量翻譯到集群內的服務。它定義了一個將流量從不了解 Kubernetes 的地方翻譯到了解 Kubernetes 的地方的方法。例如,由雲負載均衡器、集群內代理或外部硬件負載均衡器發送到 Kubernetes 服務的流量。雖然許多用例的客戶端流量源自 集群的 “外部”,但這並不是必需的。
Gateway 定義了對實現 GatewayClass 配置和行為約定的特定負載均衡器配置的請求。該資源可以由運維人員直接創建,也可以由處理 GatewayClass 的控制器創建。
由於 Gateway 規範捕獲了用戶意圖,它可能不包含規範中所有屬性的完整規範。例如,用戶可以省略地址、端口、TLS 設置等字段。這使得管理 GatewayClass 的控制器可以為用戶提供這些缺省設置,從而使規範更加可移植。這種行為將通過 GatewayClass 狀態對象來明確。
一個 Gateway 可以包含一個或多個 Route 引用,這些 Route 引用的作用是將一個子集的流量引導到一個特定的服務上。
Gateway 規範中定義了以下內容:
- GatewayClassName:定義此網關使用的 GatewayClass 對象的名稱。
- Listeners:定義主機名、端口、協議、終止、TLS 設置以及哪些路由可以附加到監聽器。
- Addresses:定義為此 Gateway 請求的網絡地址。 如果以上規範中的配置無法實現,Gateway 將處於錯誤狀態,狀態條件中會顯示詳細信息。
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"gateway.networking.k8s.io/v1beta1","kind":"Gateway","metadata":{"annotations":{},"name":"eg","namespace":"default"},"spec":{"gatewayClassName":"eg","listeners":[{"name":"http","port":8080,"protocol":"HTTP"}]}}
creationTimestamp: "2022-10-22T07:03:28Z"
generation: 1
name: eg
namespace: default
resourceVersion: "326707757"
uid: 20f37614-1814-4c4a-b3ee-8d923a1a78f8
spec:
gatewayClassName: eg
listeners:
- allowedRoutes:
namespaces:
from: Same
name: http
port: 8080
protocol: HTTP
status:
addresses:
- type: IPAddress
value: 11.11.11.11 # 如果 Envoy Gateway 部署在云上,云会创建一个 LoadBalancer 实例从而获得一个外部 IP,该 IP 为网关 IP
conditions:
- lastTransitionTime: "2022-10-22T07:03:28Z"
message: The Gateway has been scheduled by Envoy Gateway
observedGeneration: 1
reason: Scheduled
status: "True"
type: Scheduled
- lastTransitionTime: "2022-10-22T07:04:17Z"
message: Address assigned to the Gateway, 1/1 envoy Deployment replicas available
observedGeneration: 1
reason: Ready
status: "True"
type: Ready
listeners:
- attachedRoutes: 1
conditions:
- lastTransitionTime: "2022-10-22T07:03:30Z"
message: Listener is ready
observedGeneration: 1
reason: Ready
status: "True"
type: Ready
name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
從上面的示例中我們可以看到 status 中顯示了 Gateway 的狀態,如網關的 IP 地址,監聽器上附著的路由以及更新時間。
Route
Route 對象定義了特定協議的規則,用於將請求從 Gateway 映射到 Kubernetes 服務。
從 v1alpha2 開始,Gateway API 中包含四種 Route 資源類型。對於其他協議,鼓勵使用特定於實現的自定義路由類型。未來可能會向 API 添加新的路由類型。
HTTPRoute
HTTPRoute 用於多路覆用 HTTP 或終止的 HTTPS 連接。它適用於檢查 HTTP 流並使用 HTTP 請求數據進行路由或修改的情況,例如使用 HTTP Header 進行路由或在運行中修改它們。
HTTPRoute 的規範中包括:
- parentRefs:定義此路由要附加到的 Gateway。
- hostnames(可選):定義用於匹配 HTTP 請求的主機頭的主機名列表。
- rules:定義規則列表以針對匹配的 HTTP 請求執行操作。每條規則由 matches、filters(可選)和 backendRefs(可選)字段組成。
TLSRoute
TLSRoute 用於多路覆用 TLS 連接,通過 SNI 進行區分。它適用於使用 SNI 作為主要路由方法的地方,並且對 HTTP 等高級協議的屬性不感興趣。連接的字節流被代理,無需對後端進行任何檢查。
TCPRoute 和 UDPRoute
TCPRoute(和 UDPRoute)旨在用於將一個或多個端口映射到單個後端。在這種情況下,沒有可用於在同一端口上選擇不同後端的鑒別器(Discriminator),因此每個 TCPRoute 確實需要監聽器上的不同端口。你可以終止 TLS,在這種情況下,未加密的字節流被傳遞到後端。你可以選擇不終止 TLS,在這種情況下,加密的字節流被傳遞到後端。
GRCPRoute
GRPCRoute 用於路由 gRPC 流量。支持 GRPCRoute 的網關需要支持 HTTP/2,而無需從 HTTP/1 進行初始升級,因此可以保證 gRPC 流量正常流動。
Route 類型列表
下面的「路由鑒別器」一欄是指可以使用哪些信息來允許多個 Routes 共享 Listener 上的端口。
對象 | OSI 層 | 路由鑒別器 | TLS 支持 | 目 的 |
---|---|---|---|---|
HTTPRoute | 第 7 層 | HTTP 協議中的任何內容 | 僅終止 | HTTP 和 HTTPS 路由 |
TLSRoute | 第 4 層和第 7 層之間的某個位置 | SNI 或其他 TLS 屬性 | 直通或終止 | TLS 協議的路由,包括不需要檢查 HTTP 流的 HTTPS |
TCPRoute | 第 4 層 | 目的端口 | 直通或終止 | 允許將 TCP 流從 Listener 轉發到 Backends |
UDPRoute | 第 4 層 | 目的端口 | 沒有任何 | 允許將 UDP 流從監聽器轉發到後端 |
GRPCRoute | 第 7 層 | gRPC | 協議中的任何內容 | 僅終止 |
請注意,通過 HTTPRoute 和 TCPRoute 路由的流量可以在網關和後端之間進行加密(通常稱為重新加密)。無法使用現有的 Gateway API 資源對其進行配置,但實現可以為此提供自定義配置,直到 Gateway API 定義了標準化方法。
ReferenceGrant
ReferenceGrant 資源仍在實驗階段
ReferenceGrant 可用於在 Gateway API 中啟用跨命名空間引用。特別是,路由可能會將流量轉發到其他命名空間中的後端,或者 Gateway 可能會引用另一個命名空間中的 Secret。
過去,我們已經看到跨命名空間邊界轉發流量是一種理想的功能,但如果沒有 ReferenceGrant 之類的保護措施,就會出現漏洞。
如果從其命名空間外部引用一個對象,則該對象的所有者必須創建一個 ReferenceGrant 資源以顯式允許該引用,否則跨命名空間引用是無效的。
將路由添加到網關
將 Route 附加到 Gateway 表示在 Gateway 上應用的配置,用於配置底層負載均衡器或代理。Route 如何以及哪些 Route 附加到 Gateway 由資源本身控制。Route 和 Gateway 資源具有內置控件以允許或限制它們的連接方式。組織可以同時利用 Kubernetes RBAC,實施有關如何公開 Route 以及在公開在哪些 Gateway 上公開的策略。
如何將 Route 附加到網關以實現不同的組織策略和責任範圍有很大的靈活性。下面是 Gateway 和 Route 可以具有的關系:
一對一:Gateway 和 Route 可以由單個所有者部署和使用,具有一對一的關系。 一對多:Gateway 可以綁定許多 Route,這些 Route 由來自不同命名空間的不同團隊擁有。 多對一:Route 也可以綁定到多個 Gateway,允許單個 Route 同時控制跨不同 IP、負載均衡器或網絡的應用程序。